#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "dtk_types.h"
#include "dtk_debug.h"
#include "dtk_container.h"

const DString DTK_TYPE_CONTAINER = "DTKContainer";

static DBoolean release(DList* list, DLink* link, va_list args)
{
    DTKActor* actor = (DTKActor*)DLINKDATA(link);

    dtk_actor_finalize(actor);
    return DTK_FALSE;
}

void container_release (DTKActor* self)
{
    DTKContainer* container = (DTKContainer*) self;
   
    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);

    dtk_list_foreach (DLIST(container), release);  
    return;
}

static DBoolean show_all(DList* list, DLink* link, va_list args)
{
    DTKActor* actor = (DTKActor*)DLINKDATA(link);

    dtk_actor_show_all(actor);
    return DTK_FALSE;
}

static void container_show_all(DTKActor* self)
{
    DTKContainer* container = (DTKContainer*) self;
    
    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);
    dtk_list_foreach(DLIST(container), show_all);
    return;
}

static DBoolean hide_all(DList* list, DLink* link, va_list args)
{
    DTKActor* actor = (DTKActor*)DLINKDATA(link);

    dtk_actor_hide_all(actor);
    return DTK_FALSE;
}

static void container_hide_all(DTKActor* self)
{
    DTKContainer* container = (DTKContainer*) self;
    
    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);
    dtk_list_foreach(DLIST(container), hide_all);
    return;
}

static void container_add_actor(DTKActor* self, DTKActor* actor)
{
    DTKContainer* container = (DTKContainer*)self;
    if (NULL == actor)
    {
        return;
    }

    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);
    
    dtk_list_prepend(&container->list, &actor->link);
    dtk_layout_add (self->layout, actor->layout);

    dtk_actor_set_parent(actor, self);
    
    dtk_actor_update(actor, NULL, DTK_FALSE);
    return;
}

static void container_remove_actor(DTKActor* self, DTKActor* actor)
{
    DTKContainer* container = (DTKContainer*)self;
    if (NULL == actor)
    {
        return;
    }
    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);

    dtk_list_remove (&container->list, &actor->link);
    dtk_layout_remove (actor->layout);
    dtk_actor_unparent(actor);
    dtk_actor_update(self, NULL, DTK_FALSE);
    return;
}

DTKActor* dtk_container_init (DInt size, DString type, DTKActorCaps caps)
{
    DTKActor* actor;
    DTKContainer* container;
    DTKActorCallback* funcs;

    if (size < sizeof (DTKContainer))
    {
        return NULL;
    }

    actor = dtk_actor_init (size, type, caps);

    container = (DTKContainer*) actor;
    container->type = DTK_TYPE_CONTAINER;
    dtk_list_init(DLIST(container), (DPointer)container);

    funcs = DTK_ACTOR_CALLBACK(actor);

    funcs->release  = container_release;
    funcs->add      = container_add_actor;
    funcs->remove   = container_remove_actor;
    funcs->show_all = container_show_all;
    funcs->hide_all = container_hide_all;

    return actor;    
}

DInt dtk_container_get_count (DTKActor* self)
{
    DTKContainer* container = (DTKContainer*) self;

    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);

    return dtk_list_get_count (&container->list);
}

DList* dtk_container_get_list (DTKActor* self)
{
    DTKContainer* container = (DTKContainer*) self;

    DTK_TYPE_ASSERT(container, DTK_TYPE_CONTAINER);
    return &container->list;
}
